﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;

namespace MiniDatabases
{
    public class XmlDatabase : IMiniDatabase
    {
        

        #region Properties

        public string TargetFile { get; private set; }

        private XmlDocument Document { get; set; }

        #endregion

        #region Members

        private const string TableTag = "table";
        private const string TableLineTag = "line";
        private const string TableAtrName = "name";
        private const string TableAtrCurrentId = "current_id";
        private const string TableAtrColumns = "columns";
        private const string ColumnTag = "column";
        private const string ValueNull = "NULL";


        public const int CodeErrTableExists = 1;
        public const int CodeSucces = 0;

        #endregion

        #region Constructors

        public XmlDatabase(string workfile)
        {
            TargetFile = workfile;
        }

        private static XmlDocument GetDatabase(string path)
        {
            Stream stream;

            if (!File.Exists(path))
            {
                stream = File.Create(path);
                var streamWriter = new StreamWriter(stream);
                streamWriter.Write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Database>\n</Database>");
                streamWriter.Flush();
                streamWriter.Close();
            }
            
            stream = File.Open(path, FileMode.Open);
            var doc = new XmlDocument();
            doc.Load(stream);
            stream.Close();

            return doc;
        }

        #endregion

        #region Public Methods

        public int Open()
        {
            Document = GetDatabase(TargetFile);
            return CodeSucces;
        }

        public int Close()
        {
            //Document.WriteTo(new XmlTextWriter(File.Open(TargetFile, FileMode.Open),new UTF8Encoding()));
            var stream = File.Open(TargetFile, FileMode.Open);
            Document.Save(stream);
            stream.Close();
            return CodeSucces;
        }

        public int Create(string tableName, params string[] columns )
        {
            var root = Document.DocumentElement;

            if(GetTableNode(tableName) != null)
                return CodeErrTableExists;

            var tableNode = Document.CreateElement(TableTag);

            tableNode.SetAttribute(TableAtrName, tableName);

            var columnsDefinition = "";

            foreach (var column in columns)
            {
                columnsDefinition += column + "|";
            }

            tableNode.SetAttribute(TableAtrColumns, columnsDefinition);
            tableNode.SetAttribute(TableAtrCurrentId, "1");

            root.AppendChild(tableNode);

            return CodeSucces;
        }

        public int Insert(string table, Dictionary<string,string> colNvalue)
        {
            var node = GetTableNode(table);
            var cols = node.Attributes[TableAtrColumns].Value.Split(new[] {'|'},StringSplitOptions.RemoveEmptyEntries);

            var lineId = Int32.Parse(node.Attributes[TableAtrCurrentId].Value);
            node.Attributes[TableAtrCurrentId].Value = (lineId + 1).ToString("D");

            var line = Document.CreateElement(TableLineTag);
            line.SetAttribute("id", lineId.ToString("D"));

            foreach (var col in cols)
            {
                line.SetAttribute(col, colNvalue.ContainsKey(col) ? colNvalue[col] : string.Empty);
            }

            node.AppendChild(line);
            return CodeSucces;
        }

        public List<string[]> Select(string table, params string[] columns)
        {
            var node = GetTableNode(table);
            var nbOfColumns = columns.Count();
            var result = new List<string[]>();

            var lines = node.ChildNodes;
            for (var i = 0; i < lines.Count; i++)
            {
                var lineRes = new string[nbOfColumns];
                var k = 0;
                foreach (var column in columns)
                {
                    lineRes[k++] = lines[i].Attributes[column].Value;
                }
                result.Add(lineRes);
            }

            return result;
        }

        public int Update(string table, Dictionary<string, string> values, params int[] ids)
        {
            return -1;
        }

        public int Delete(string table, params int[] ids)
        {
            return -1;
        }

        #endregion

        #region Private Methods

        private XmlNode GetTableNode(string tableName)
        {
            var root = Document.DocumentElement;
            var result = root.GetElementsByTagName(TableTag);

            for (var i = 0; i < result.Count; i++)
            {
                if (result[i].Attributes[TableAtrName].Value.Equals(tableName))
                {
                    return result[i];
                }
            }

            return null;
        }

        #endregion
    }
}
